 Programando com DirectDraw no Visual C++ 
Por Geovanni Soares 



Neste Tutorial faremos um breve resumo sobre o DirexcDraw e vamos criar um programa simples, que inicia o DirectDraw, carrega um arquivo Bitmap para memria de vdeo, carrega uma paleta e desenha a imagem na tela. No final desse artigo voc poder fazer o Download do cdigo fonte desse tutorial em Visual C++ .

O DirectDraw 

DirectDraw  um dos componentes para programao da API DirectX da Microsoft, que permite voc manipular diretamente a memria da placa de vdeo. Com isso, o aplicativo tem uma performance superior aquela, que voc usa quando programa com a interface (GDI) do Windows.

O DirectDraw  essencialmente um gerenciador de memria de vdeo. Ele permite que o programador armazene e manipule bitmaps, diretamente na memria de vdeo. Poder trocar informaes da memria de vdeo para a memria de vdeo,  muito mais rpido do que trocar informaes da memria do sistema para a memria de vdeo. Outra vantagem,  que o processo de manipulao de dados de imagens,  feito pela placa de vdeo, e isto permite que o processador central ocupe o seu tempo fazendo outras coisas.

Programando

Pressupondo que voc j tenha instalados em seu computador o SDK do DirectX (download pode ser feito na Microsoft em www.microsoft.com/directx) e o Visual C++, vamos comear a programar! 

Inicie um novo projeto Win32 Application (no Win32 Console Application). Se voc no sabe como fazer isto, recomendo que pare de ler este tutorial e procure um tutorial de Visual C++ aqui mesmo neste site. Quando aprender, volte a este tutorial. 

Agora precisamos ligar as bibliotecas do DirectX ao projeto. No Visual C++ v em Project, Settings, e clique na aba LINK. Em "Object/Library Modules", no incio da linha (antes de kernel32.lib), adicione dxguid.lib ddraw.lib. Feito isto, clique em OK. Agora voc est pronto para escrever o nosso programa em DirectDraw. 

Crie um novo arquivo chamado tutorial.cpp; adicione os arquivos de cabealhos do windows e do DirectDraw. O arquivo de cabealho "ddutil.h", e o "ddutil.cpp", podem ser encontrados em um dos exemplos do DirectDraw. Voc deve localiza-los e copia-los para o diretrio do nosso aplicativo. Estes aquivos j contm as rotinas necessrias para manipulao de paletas e bitmaps para o DirectDraw.

#include 
#include 
#include "ddutil.h" 

A seguir declaramos as variveis globais para o nosso aplicativo. A varivel app_ativo ser ultilizada para saber se o aplicativo est ativo, pois se tentarmos desenhar na superfcie do DirectDraw com o aplicativo minimizado, ocorrer um erro. A varivel cordofundo armazena a cor que ultilizaremos para limpar a superfcie do DirectDraw. 

#define NOME "TUTORIAL" 
char szMensagem[] = "Pressione ESC para Sair";
bool app_ativo = false; 
HWND hWnd =NULL; 
COLORREF corfundo = RGB(0,0,0); 

Agora declaramos as variveis ultilizadas pelo DirectDraw. A varivel pDirectDraw  um ponteiro para o objeto DirectDraw que ser criado. A varivel pDDsPrimaria ser um ponteiro para a superfcie primria, onde ser mostrado tudo que for desenhado. A varivel pDDSTraseira  um ponteiro para a superfcie que no  visvel, onde realmente desenhamos e depois trocamos com a superfcie primria. A varivel pDDPaleta  um ponteiro para a paleta de cores que ser ultilizada pelo DirectDraw. E pDDSImagem  um ponteiro de uma superfcie onde ser armazenada a imagem que ultilizaremos no aplicativo.

LPDIRECTDRAW7 pDirectDraw; 
LPDIRECTDRAWSURFACE7 pDDSPrimaria; 
LPDIRECTDRAWSURFACE7 pDDSTraseira; 
LPDIRECTDRAWPALETTE pDDPaleta; 
LPDIRECTDRAWSURFACE7 pDDSImagem;
Definio para a Funo WindowProc() 

LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);

Vamos Criar uma funo para iniciar o DirectDraw, selecionar o modo da tela, criar as superfcies, carregar a paleta de cores e a bitmap. 


HRESULT IniciaDirectDraw() 
{

HRESULT hRet;
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;

pDirectDraw =NULL; 
pDDSPrimaria =NULL; 
pDDSTraseira =NULL; 
pDDPaleta =NULL; 
pDDSImagem =NULL;

Abaixo executamos o DirectDrawCreateEx() para criarmos um objeto DirectDraw, e se a funo retornar um valor direfente de DD_OK, significa que no foi possvel criar o Objeto DirectDraw. 

hRet = DirectDrawCreateEx(NULL, (VOID**)&pDirectDraw, IID_IDirectDraw7, NULL);
if (hRet != DD_OK)
return MessageBox(hWnd,NOME,"Falha DirectDrawCreateEx",0);

A seguir definimos como o nosso aplicativo ir se comportar. Antes que seja possvel mudar o modo da tela, devemos no mnimo, especificar os parmetros DDSCL_EXCLUSIVE e DDSCL_FULLSCREEN do mtodo SetCooperativeLevel() do DirectDraw. Isso dar ao aplicativo o controle completo da tela de vdeo, e nenhum outro aplicativo poder ultiliza-la. O parmetro DDSCL_FULLSCREEN, determina que o aplicativo vai ocupar a tela inteira e somente ele poder escrever na tela. A rea de trabalho ainda est disponvel mas est oculta. Para acessa-la voc precisa pressionar (ALT+TAB). 

hRet = pDirectDraw->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
if (hRet != DD_OK)
return MessageBox(hWnd,NOME,"Falha SetCooperativeLevel",0);
Depois que voc definiu como o nosso aplicativo ir se comportar, utilizaremos SetDisplayMode() para selecionar qual resoluo e a quantidade de cores que o aplicativo trabalhar. Em nosso aplicativo uzaremos 640x480 e 256 cores. 

hRet = pDirectDraw->SetDisplayMode(640,480, 8, 0, 0);
if (hRet != DD_OK)
return MessageBox(hWnd,NOME,"Falha SetDisplayMode",0);

Agora ser criada a superfcie primria DirectDraw para o nosso aplicativo, ultilizando o mtodo CreateSurface(). 

ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
hRet = pDirectDraw->CreateSurface(&ddsd, &pDDSPrimaria, NULL);
if (hRet != DD_OK)
return MessageBox(hWnd,NOME,"Falha CreateSurface",0);

Depois que a superfcie primria foi criada, adquirimos o ponteiro da superfcie traseira do DirectDraw. 

ZeroMemory(&ddscaps, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
hRet = pDDSPrimaria->GetAttachedSurface(&ddscaps, &pDDSTraseira);
if (hRet != DD_OK)
return MessageBox(hWnd,NOME,"Falha GetAttachedSurface",0);

Os cdigos abaixo iro carregar uma bitmap, onde ser ultilizada a sua paleta de cores como padro de nosso aplicativo. A funo DDLoadPalette()  parte das funes que so encontradas no arquivo "DDUtil.cpp" que foi mencionado anteriormente. 

pDDPaleta = DDLoadPalette(pDirectDraw, "pdj.bmp"); 
if (pDDPaleta == NULL) 
return MessageBox(hWnd,NOME,"Falha DDLoadPalette",0);

Agora ultilizamos o mtodo SetPalette() para definirmos a pDDPaleta como padro. Voc pode mudar a paleta de cores quando quiser, bastando carregar uma nova paleta com o cdigo acima, e em seguida ultilizar o mtodo SetPalete() do DirectDraw. 

hRet = pDDSPrimaria->SetPalette(pDDPaleta); 
if(hRet != DD_OK) 
return MessageBox(hWnd,NOME,"Falha SetPalette",0);
A seguir carregamos a bitmap "pdj.bmp" ultilizando a funo DDLoadBitmap() do arquivo "ddutil.cpp", que retornar o ponteiro da superfcie DirectDraw onde estar armazenada a bitmap. 

pDDSImagem = DDLoadBitmap(pDirectDraw, "pdj.bmp",0,0); 
if(pDDSImagem ==NULL) 
return MessageBox(hWnd,NOME,"Falha DDReLoadBitmap",0);


//se chegou at aqui, ocorreu tudo bem ao iniciar o DirectDraw
return DD_OK;
}

Vamos agora criar um procedimento chamado LiberaDirectDraw, que ser ultilizado quando o aplicativo for finalizado. Este procedimento vai liberar a memria ultilizada pelo DirectDraw e das superfcies. 

//Libera a Memria ultilizada pelo DirectDraw
void LiberaDirectDraw()
{

if (pDirectDraw != NULL)
{
if (pDDSPrimaria != NULL)
{
pDDSPrimaria->Release();
pDDSPrimaria = NULL;
}
pDirectDraw->Release();
pDirectDraw = NULL;

if (pDDSImagem != NULL)
{
pDDSImagem->Release();
pDDSImagem = NULL;
}

}
}

O cdigo seguinte define e registra a classe da janela, cria e mostra a janela na tela. 

int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInsnt,
LPSTR lpszArgs, int nWinMode)
{
MSG msg;
WNDCLASS wcl;

/////////////////////////////////////////////////////////
//Define e Registra a classe para a janela do aplicativo
/////////////////////////////////////////////////////////
wcl.style = CS_HREDRAW | CS_VREDRAW;
wcl.lpfnWndProc = WindowProc;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hInstance = hThisInst;
wcl.hIcon = NULL;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH )GetStockObject(BLACK_BRUSH);
wcl.lpszMenuName = NOME;
wcl.lpszClassName = NOME;

if(!RegisterClass (&wcl)) return 0; 

//////////////////////////////////
//Cria a Janela
//////////////////////////////////
hWnd = CreateWindowEx(0,
NOME,
"Tutorial DirectDraw",
WS_POPUP,
0,
0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
hThisInst,
NULL);
ShowWindow(hWnd, nWinMode); 
UpdateWindow(hWnd); 
SetFocus(hWnd); 
Agora chamaremos a funo IniciaDirectDraw() que foi criada anteriormente. Se ocorrer qualquer erro dentro desta funo, esta retornar um valor diferente de DD_OK e o aplicativo ser finalizado. 

//////////////////////////////////////////////////////////////////
//Chama a Funo e se ocorrer qualquer erro, finaliza o aplicativo
//////////////////////////////////////////////////////////////////
if (IniciaDirectDraw()!=DD_OK) 
{
DestroiDirectDraw();
return false;
}

Abaixo temos o lao de mensagens padro de um aplicativo Windows. Ser verificado se o aplicativo est ativo, para que seja possvel desenhar a bitmap e escrever um texto na superfcie traseira, efetuar as trocas entre as superfcies primria e traseira, e depois limpar a superfcie traseira com a cor especificada na varivel corfundo 

while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, NULL, 0, 0))
return msg.wParam;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (app_ativo)//Se o Aplicativo estiver ativo, desenha a Imagem
{

RECT r;
HDC hdc;
//define qual a area da imagem que ser desenhada
r.left=0;
r.top=0;
r.right=212;
r.bottom=61;
//Desenha a imagem na posicao 200 x, 200 y na superfcie traseira
pDDSTraseira->BltFast(200, 200, pDDSImagem,&r, DDBLTFAST_NOCOLORKEY );

if (pDDSTraseira->GetDC(&hdc) == DD_OK) 
{ 
SetBkColor(hdc, RGB(0, 0, 0)); 
SetTextColor(hdc, RGB(255, 255, 0)); 
TextOut(hdc, 0, 0, szMensagem, lstrlen(szMensagem)); 
pDDSTraseira->ReleaseDC(hdc); 
} 

pDDSPrimaria->Flip(NULL, 0); 

DDBLTFX ddbltfx;
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = corfundo;
pDDSTraseira->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);

}
else
{
// Aguarda por novas mensagens
WaitMessage();
}
}

}
Abaixo temos os cdigos que recebero as mensagens do windows. 

LRESULT CALLBACK WindowProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{

case WM_ACTIVATE: 
app_ativo = !((BOOL)HIWORD(wParam));
return 0L;

case WM_DESTROY: 
DestroiDirectDraw();
PostQuitMessage(0);
return 0L;

case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostMessage(hwnd, WM_CLOSE, 0, 0);
return 0L;
break;
}
break;


default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
Ufa! fim dos cdigos. 

Notas Finais

Voc pode efetuar o download do projeto em Visual C++ deste tutorial Clicando aqui.

Se voc tiver qualquer dvida sobre este tutorial, entre em nosso FORUM e deixe a sua mensgem que terei o maior prazer em ajud-lo.

Em breve estaremos disponibilizando outros tutorias sobre o DirectX em geral. Espero t-lo ajudado.

